#include <ubt_com/log/spdlog.h>

namespace ubt_com
{

// ubtLog::ubtLog(std::string node_name, int size, int count)
// {
//     // //打印到终端
//     // auto console = spdlog::stdout_color_mt("console");

//     //打印到日志文件中
//     std::string file_dir = "~/.ros/log/" + node_name + "/" + node_name + ".log";
//     auto logger = spdlog::rotating_logger_mt(node_name, file_dir, size, count);
 
//     spdlog::set_default_logger(logger);
//     spdlog::set_level(spdlog::level::info);
//     // spdlog::set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%g:%#] [%n:%l] %v");
 
//     // spdlog::info("Welcom to spdlog!");
// }

ubtLog::ubtLog(const std::string fileName, const int maxFileSize, const int keep, 
			const OutMode outMode, const OutPosition outPos, const OutLevel outLevel)
{
    logInit = false;
	fileName_ = fileName;
    auto fileDirAndName = "/home/ubt/.ros/log/" + fileName + "/" + fileName + ".log";
    this->init(fileDirAndName, maxFileSize, keep, outMode, outPos, outLevel);
	// this->delOldFile(fileName, keep);
	diskUsageThread_ = std::thread(&ubtLog::checkDiskUsageAndDeleteLogs, this);
}

ubtLog::ubtLog(const std::string fileName, const int keep,
               const OutMode outMode, const OutPosition outPos, const OutLevel outLevel)
{
    logInit = false;
	fileName_ = fileName;
    auto fileDirAndName = "/home/ubt/.ros/log/" + fileName + "/" + fileName + ".log";
    this->init(fileDirAndName, 0, keep, outMode, outPos, outLevel);
	this->delOldFile(fileName, keep);
	diskUsageThread_ = std::thread(&ubtLog::checkDiskUsageAndDeleteLogs, this);
}

bool ubtLog::init(const std::string fileDirAndName, const int maxFileSize, const int keep, 
			  const OutMode outMode, const OutPosition outPos, const OutLevel outLevel)
{
    if (logInit)
    {
        return false;
    }
    logInit = true;

	try 
	{
		// const char* pFormat = "[%Y-%m-%d %H:%M:%S.%e] <thread %t> [%^%l%$]\n[%@,%!]\n%v\n";
		const char* pFormat = "[%Y-%m-%d %H:%M:%S.%e][%^%l%$][%!] %v";
		//sink容器
		std::vector<spdlog::sink_ptr> vecSink;

		//控制台
		if (outPos & CONSOLE)
		{
			auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
			//console_sink->set_level(spdlog::level::trace);
			console_sink->set_pattern(pFormat);
			vecSink.push_back(console_sink);
		}

		//文件
		if ((outPos & FILE) && maxFileSize > 0)
		{
			auto file_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(fileDirAndName, maxFileSize, keep);
			//file_sink->set_level(spdlog::level::trace);
			file_sink->set_pattern(pFormat);
			vecSink.push_back(file_sink);
		}
		else
		{
			auto file_sink = std::make_shared<spdlog::sinks::daily_file_sink_mt>(fileDirAndName, 0, 0, false, keep);
            file_sink->set_pattern(pFormat);
            vecSink.push_back(file_sink);
		}

		//设置logger使用多个sink
		if (outMode == ASYNC)//异步
		{
			spdlog::init_thread_pool(102400, 1);
			auto tp = spdlog::thread_pool();
			pLogger = std::make_shared<spdlog::async_logger>(LOG_NAME, begin(vecSink), end(vecSink), tp, spdlog::async_overflow_policy::block);
		}
		else//同步
		{
			pLogger = std::make_shared<spdlog::logger>(LOG_NAME, begin(vecSink), end(vecSink));
		}
		pLogger->set_level((spdlog::level::level_enum)outLevel);

		//遇到warn级别，立即flush到文件
		pLogger->flush_on(spdlog::level::warn);
		//定时flush到文件，每三秒刷新一次
		spdlog::flush_every(std::chrono::seconds(3));
		spdlog::register_logger(pLogger);
    }
	catch(const spdlog::spdlog_ex& ex)
	{
		std::cout << "Log initialization failed: " << ex.what() << std::endl;
		return false;
	}
    return true;
}

bool ubtLog::delOldFile(const std::string fileName, const int keep)
{
    std::string fileDir = "/home/ubt/.ros/log/" + fileName + "/";
    std::vector<std::string> files;

    DIR* dir;
    struct dirent* ent;
    if ((dir = opendir(fileDir.c_str())) != nullptr)
    {
        while ((ent = readdir(dir)) != nullptr)
        {
            std::string filename = ent->d_name;
            if (filename != "." && filename != "..")
            {
                files.push_back(filename);
            }
        }
        closedir(dir);
    }
    else
    {
		std::cout << "SPDLOG: delOldFile open "<< fileDir <<" error!!!" << std::endl;
        return false;
    }

    // 对文件进行排序，按照文件名中的日期从新到旧排序
    std::sort(files.begin(), files.end(), [fileName](const std::string& a, const std::string& b) {
        std::string dateA = a.substr(fileName.length() + 1, 10);
        std::string dateB = b.substr(fileName.length() + 1, 10);
        return dateA > dateB;
    });

    for (int i = keep; i < files.size(); ++i)
    {
        std::string filePath = fileDir + files[i];
        std::remove(filePath.c_str());
    }

    return true;
}

void ubtLog::checkDiskUsageAndDeleteLogs() {
    while (true) {
        struct statvfs buf;
        if (statvfs("/home/ubt/.ros/log/", &buf) == 0) {
            unsigned long totalBlocks = buf.f_blocks * buf.f_frsize;
            unsigned long freeBlocks = buf.f_bfree * buf.f_frsize;
            double usedPercentage = 100.0 - ((double)freeBlocks / totalBlocks) * 100.0;

            if (usedPercentage > 70.0) {
                // std::string todayDate = getTodayDate();
                // std::vector<std::string> logFiles = getLogFiles("/home/ubt/.ros/log/");
                // for (const std::string& file : logFiles) {
                //     if (file.find(todayDate) == std::string::npos) {
                //         std::string filePath = "/home/ubt/.ros/log/" + file;
                //         std::remove(filePath.c_str());
                //     }
                // }
				delOldFile(fileName_, 1);
            }
        }

        std::this_thread::sleep_for(std::chrono::hours(1));
        // std::this_thread::sleep_for(std::chrono::milliseconds(10000));
    }
}

// std::string ubtLog::getTodayDate() {
//     auto now = std::chrono::system_clock::now();
//     std::time_t now_c = std::chrono::system_clock::to_time_t(now);
//     std::tm* now_tm = std::localtime(&now_c);

//     std::ostringstream oss;
//     oss << (now_tm->tm_year + 1900) << "-" << (now_tm->tm_mon + 1) << "-" << now_tm->tm_mday;
//     return oss.str();
// }

// std::vector<std::string> ubtLog::getLogFiles(const std::string& directory) {
//     std::vector<std::string> files;
//     for (const auto& entry : std::filesystem::directory_iterator(directory)) {
//         if (!entry.is_directory()) {
//             files.push_back(entry.path().filename().string());
//         }
//     }
//     return files;
// }

ubtLog::~ubtLog()
{
	diskUsageThread_.join();
	spdlog::drop_all();
    spdlog::shutdown();
}

}
